package com.zzsz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;

import com.zzsz.domain.Product;
import com.zzsz.domain.ProductCategory;
import com.zzsz.domain.WaringRecipient;
import com.zzsz.mapper.ProductWarnMapper;
import com.zzsz.mapper.RecipientMapper;
import com.zzsz.service.WarnService;
import com.zzsz.utils.IEmailService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 预警管理服务实现类
 *
 * @author 超级无敌张恒阳大王
 * @date 1/9/2025
 * @desc 提供预警相关的分类树形结构、商品关联等功能
 */
@Slf4j
@Service
public class WarnServiceImpl implements WarnService {

	@Autowired
	private ProductWarnMapper productWarnMapper;

	@Autowired
	private RecipientMapper recipientMapper;

	@Autowired
	private IEmailService emailService;

	/**
	 * 获取带商品的分类树形结构
	 */
	@Override
	public List<Tree<Integer>> getCategoryTree() {
		try {
			// 1. 查询所有分类（MyBatis一般返回空List，无需判断null）
			List<ProductCategory> categoryList = productWarnMapper.selectAllCategory();
			log.info("💡 数据库原始分类数量: {}", categoryList.size());

			// 打印问题数据（调试用）
			categoryList.forEach(cat -> {
				if (Objects.isNull(cat)) {
					log.warn("⚠️ 发现空分类对象");
				} else {
					if (Objects.isNull(cat.getCategoryId())) {
						log.warn("⚠️ 分类ID为空: {}", cat);
					}
					if (StringUtils.isBlank(cat.getCategoryName())) {
						log.warn("⚠️ 分类名称为空: ID={}", cat.getCategoryId());
					}
				}
			});

			if (CollectionUtil.isEmpty(categoryList)) {
				log.info("📌 数据库返回空分类列表");
				return CollectionUtil.newArrayList();
			}

			// 2. 过滤分类：对象非空 + 分类ID非空 + 分类名称非空
			List<ProductCategory> validCategoryList = categoryList.stream()
					.filter(category ->
							Objects.nonNull(category.getCategoryId())
									&& StringUtils.isNotBlank(category.getCategoryName())
					)
					.peek(category -> {
						// 确保父ID非空，默认为0（根节点）
						if (Objects.isNull(category.getParentId())) {
							category.setParentId(0);
						}
					})
					.collect(Collectors.toList());
			log.debug("🔍 2.过滤后有效分类数量: {}", validCategoryList.size());
			// 3. 提取分类ID（避免空列表查商品）
			List<Integer> categoryIds = validCategoryList.stream()
					.map(ProductCategory::getCategoryId)
					.collect(Collectors.toList());
			log.debug("🔍 3.有效分类ID列表: {}", categoryIds);

			// 4. 按分类ID分组商品（避免空列表导致SQL错误）
			Map<Integer, List<Product>> productMap = new HashMap<>();
			if (CollectionUtil.isNotEmpty(categoryIds)) {
				List<Product> products = productWarnMapper.selectByCategoryIds(categoryIds);
				productMap = products.stream()
						.filter(p -> Objects.nonNull(p) && Objects.nonNull(p.getCategoryId()))
						.collect(Collectors.groupingBy(Product::getCategoryId));
			}
			log.debug("🔍 4.按分类ID分组商品数量: {}", productMap.size());
			// 5. 转换为DTO（避免污染数据库实体）
			Map<Integer, List<Product>> finalProductMap = productMap;
			List<CategoryWithProductDTO> categoryDTOList = validCategoryList.stream()
					.map(category -> {
						CategoryWithProductDTO dto = new CategoryWithProductDTO();
						BeanUtil.copyProperties(category, dto);
						dto.setProducts(finalProductMap.getOrDefault(category.getCategoryId(), CollectionUtil.newArrayList()));
						return dto;
					})
					.collect(Collectors.toList());
			log.debug("🔍 5.转换为DTO数量: {}", categoryDTOList.size());
			categoryDTOList.forEach(dto -> log.debug("📊 DTO详情: categoryId={}, parentId={}, name={},products={}", dto.getCategoryId(), dto.getParentId(), dto.getCategoryName(), dto.getProducts()));

			// 6. 显式配置树形结构，用Hutool构建树形
			TreeNodeConfig treeConfig = new TreeNodeConfig();
			treeConfig.setIdKey("categoryId");
			treeConfig.setParentIdKey("parentId");
			treeConfig.setNameKey("categoryName");

			List<Tree<Integer>> treeList = TreeUtil.build(categoryDTOList, 0, treeConfig, (dto, tree) -> {
				tree.setId(dto.getCategoryId());
				tree.setParentId(dto.getParentId());
				tree.setName(dto.getCategoryName());
				tree.putExtra("products", dto.getProducts());
			});

			log.debug("🔍 6.构建树形结构: {}", treeList);
			return treeList;

		} catch (Exception e) {
			log.error("获取带商品的分类树形结构失败", e);
			throw new RuntimeException("分类树加载失败，请联系管理员"); // 实际项目建议用自定义业务异常
		}
	}

	/**
	 * 分类+商品DTO（非数据库实体，仅用于返回结果）
	 */
	@Data
	private static class CategoryWithProductDTO {
		private Integer categoryId;
		private Integer parentId;
		private String categoryName;
		private List<Product> products;
	}


	/**
	 * 设置(变更)预警状态
	 */
	@Transactional // 事务管理
	@Override
	public void setWarnStatus(Product product) {

		log.debug("传入的商品信息{}", product.toString());
		// 判断是变为预警还是变为正常(预警状态 0-未预警 1-预警中)
		if (product.getAlertStatus() == 0) {
			// 变为预警
			product.setAlertStatus(1); // 状态变为预警中
			productWarnMapper.setWarnStatus(product);// 只用到对象里面的两个属性：productId和alertStatus
			// log.debug("商品{}变为预警",product.toString());
			// 由于前端的分类对象与后端的商品对象不同,只能根据传回来的id重新查询商品的信息
			Product warnProduct = productWarnMapper.selectById(product.getProductId());
			log.debug("商品id:{}", product.getProductId());
			log.debug("商品{}变为预警", warnProduct.toString());

			// 根据商品分类查询要接受预警的人
			Integer categoryId = warnProduct.getCategoryId(); // 商品的分类id
			log.debug("商品的分类id:{}", categoryId);
			// 根据分类id查询要接受预警的人的信息(邮箱,姓名)
			WaringRecipient recipient = recipientMapper.selectByCategoryId(categoryId);
			if (Objects.isNull(recipient)) {
				log.warn("未找到分类为{}的预警接收人,将发送预警信息给仓库主管", categoryId);
				recipient = recipientMapper.selectMaster();
			}
			log.debug("要接受预警的人信息:{}", recipient.toString());

			// 发送预警邮件
			emailService.sendText("2114403794@qq.com", recipient.getRecipientEmail(), "商品预警", recipient.getRecipientName()+" \r\n商品" + warnProduct.getProductName() + "库存达到阈值,请尽快处理");
		} else {
			// 变为正常
			product.setAlertStatus(0); // 状态变为正常
			productWarnMapper.setWarnStatus(product);// 只用到对象里面的两个属性：productId和alertStatus
		}
	}

	/**
	 * 更新预警阈值
	 */
	@Override
	public void updateThreshold(Product product) {
		// 先判断是否存在
		Product productFromDb = productWarnMapper.selectById(product.getProductId());
		if (Objects.isNull(productFromDb)) {
			throw new RuntimeException("商品不存在");
		}
		// 变更预警阈值(只修改一个属性)
		productWarnMapper.updateThreshold(product);
	}


	/**
	 * 查询所有商品
	 *
	 * @return 商品列表
	 */
	@Override
	public List<Product> selectAllProduct() {
		return productWarnMapper.selectAllProduct();
	}
}